﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Management;

namespace System.Peppers.Wmi
{
    /// <summary>
    /// The Win32_Processor WMI class represents a device that can interpret a sequence of instructions on a computer running on a Windows operating system. On a multiprocessor computer, one instance of the Win32_Processor class exists for each processor.
    /// </summary>
    public sealed class Processor : SystemElement
    {
        #region Static
        private static class WmiProperties
        {
            public const string AddressWidth = "AddressWidth",
                Architecture = "Architecture",
                CpuStatus = "CpuStatus",
                CurrentClockSpeed = "CurrentClockSpeed",
                DataWidth = "DataWidth",
                DeviceID = "DeviceID",
                ExtClock = "ExtClock",
                Family = "Family",
                L2CacheSize = "L2CacheSize",
                L2CacheSpeed = "L2CacheSpeed",
                L3CacheSize = "L3CacheSize",
                L3CacheSpeed = "L3CacheSpeed",
                LoadPercentage = "LoadPercentage",
                MaxClockSpeed = "MaxClockSpeed",
                NumberOfCores = "NumberOfCores",
                NumberOfLogicalProcessors = "NumberOfLogicalProcessors",
                ProcessorId = "ProcessorId",
                ProcessorType = "ProcessorType",
                UniqueId = "UniqueId";
        }

        /// <summary>
        /// Enumerates processors on the system
        /// </summary>
        /// <returns>List of processors</returns>
        public static IEnumerable<Processor> GetProcessors()
        {
            foreach (ManagementObject item in GetInstances(WmiClasses.Win32_Processor))
            {
                yield return new Processor(item);
            }
        }

        /// <summary>
        /// Enumerates processors on a remote system
        /// </summary>
        /// <param name="remoteParams">Connection options for remote system</param>
        /// <returns>List of processors</returns>
        public static IEnumerable<Processor> GetProcessors(WmiRemoteParameters remoteParams)
        {
            foreach (ManagementObject item in GetInstances(WmiClasses.Win32_Processor, remoteParams))
            {
                yield return new Processor(item);
            }
        }
        #endregion

        internal Processor(ManagementObject wmiObject)
            : base(wmiObject)
        { }

        /// <summary>
        /// On a 32-bit operating system, the value is 32 and on a 64-bit operating system it is 64. 
        /// </summary>
        public ushort AddressWidth
        {
            get { return Convert.ToUInt16(this[WmiProperties.AddressWidth] ?? 0); }
        }

        /// <summary>
        /// Processor architecture used by the platform.
        /// </summary>
        public ProcessorArchitecture Architecture
        {
            get { return (ProcessorArchitecture)Convert.ToUInt16(this[WmiProperties.Architecture] ?? 0); }
        }

        /// <summary>
        /// Current status of the processor. Status changes indicate processor usage, but not the physical condition of the processor.
        /// </summary>
        public CpuStatus CpuStatus
        {
            get { return (CpuStatus)Convert.ToUInt16(this[WmiProperties.CpuStatus] ?? 0); }
        }

        /// <summary>
        /// Current speed of the processor, in MHz.
        /// </summary>
        public uint CurrentClockSpeed
        {
            get { return Convert.ToUInt32(this[WmiProperties.CurrentClockSpeed] ?? 0); }
        }

        /// <summary>
        /// On a 32-bit processor, the value is 32 and on a 64-bit processor it is 64. 
        /// </summary>
        public ushort DataWidth
        {
            get { return Convert.ToUInt16(this[WmiProperties.DataWidth] ?? 0); }
        }

        /// <summary>
        /// Unique identifier of a processor on the system.
        /// </summary>
        public string DeviceID
        {
            get { return Convert.ToString(this[WmiProperties.DeviceID]); }
        }

        /// <summary>
        /// External clock frequency, in MHz. If the frequency is unknown, this property is set to 0.
        /// </summary>
        public uint ExternalClockSpeed
        {
            get { return Convert.ToUInt32(this[WmiProperties.ExtClock] ?? 0); }
        }

        /// <summary>
        /// Size of the Level 2 processor cache. A Level 2 cache is an external memory area that has a faster access time than the main RAM memory.
        /// </summary>
        public uint L2CacheSize
        {
            get { return Convert.ToUInt32(this[WmiProperties.L2CacheSize] ?? 0); }
        }

        /// <summary>
        /// Clock speed of the Level 2 processor cache. A Level 2 cache is an external memory area that has a faster access time than the main RAM memory.
        /// </summary>
        public uint L2CacheSpeed
        {
            get { return Convert.ToUInt32(this[WmiProperties.L2CacheSpeed] ?? 0); }
        }

        /// <summary>
        /// Size of the Level 3 processor cache. A Level 3 cache is an external memory area that has a faster access time than the main RAM memory.
        /// Constraint: Windows Server 2003, Windows XP, and Windows 2000:  This property is not available.
        /// </summary>
        public uint L3CacheSize
        {
            get { return Convert.ToUInt32(this[WmiProperties.L3CacheSize] ?? 0); }
        }

        /// <summary>
        /// Clockspeed of the Level 3 property cache. A Level 3 cache is an external memory area that has a faster access time than the main RAM memory.
        /// Constraint: Windows Server 2003, Windows XP, and Windows 2000:  This property is not available.
        /// </summary>
        public uint L3CacheSpeed
        {
            get { return Convert.ToUInt32(this[WmiProperties.L3CacheSpeed] ?? 0); }
        }

        /// <summary>
        /// Maximum speed of the processor, in MHz.
        /// </summary>
        public uint MaxClockSpeed
        {
            get { return Convert.ToUInt32(this[WmiProperties.MaxClockSpeed] ?? 0); }
        }

        /// <summary>
        /// Number of cores for the current instance of the processor. A core is a physical processor on the integrated circuit. For example, in a dual-core processor this property has a value of 2.
        /// Constraint: Windows Server 2003, Windows XP, and Windows 2000:  This property is not available.
        /// </summary>
        public uint NumberOfCores
        {
            get { return Convert.ToUInt32(this[WmiProperties.NumberOfCores] ?? 0); }
        }

        /// <summary>
        /// Number of logical processors for the current instance of the processor. For processors capable of hyperthreading, this value includes only the processors which have hyperthreading enabled.
        /// Constraint: Windows Server 2003, Windows XP, and Windows 2000:  This property is not available.
        /// </summary>
        public uint NumberOfLogicalProcessors
        {
            get { return Convert.ToUInt32(this[WmiProperties.NumberOfLogicalProcessors] ?? 0); }
        }

        /// <summary>
        /// Processor information that describes the processor features. For an x86 class CPU, the field format depends on the processor support of the CPUID instruction. If the instruction is supported, the property contains 2 (two) DWORD formatted values. The first is an offset of 08h-0Bh, which is the EAX value that a CPUID instruction returns with input EAX set to 1. The second is an offset of 0Ch-0Fh, which is the EDX value that the instruction returns. Only the first two bytes of the property are significant and contain the contents of the DX register at CPU reset—all others are set to 0 (zero), and the contents are in DWORD format.
        /// </summary>
        public string ProcessorId
        {
            get { return Convert.ToString(this[WmiProperties.ProcessorId]); }
        }

        /// <summary>
        /// Primary function of the processor.
        /// </summary>
        public ProcessorType ProcessorType
        {
            get { return (ProcessorType)Convert.ToUInt16(this[WmiProperties.ProcessorType] ?? 2); }
        }

        /// <summary>
        /// Globally unique identifier for the processor. This identifier may only be unique within a processor family.
        /// </summary>
        public string UniqueId
        {
            get { return Convert.ToString(this[WmiProperties.UniqueId]); }
        }

        /// <summary>
        /// Processor family type. 
        /// </summary>
        public ProcessorFamily Family
        {
            get { return (ProcessorFamily)Convert.ToUInt16(this[WmiProperties.Family] ?? 2); }
        }
    }
}
